﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Orbs2Revengeance
{
    public struct CritterType
    {
        public float curve;

        public Color foreColour;
        public Color backColour;
     
        public float headHeight;
        public float headAngle;
       
        public float leftArmLength;
        public float leftArmAngle;

        public float rightArmLength;
        public float rightArmAngle;

        public Point bodyPosition;
        public float bodyHeight;
        public float bodyWidth;

        public float waistWidth;

        public float leftLegLength;
        public float leftLegAngle;

        public float rightLegLength;
        public float rightLegAngle;
    }

    public struct CritterMotionType
    {        
        public float headSwingRange;
        public float headSwingRate;
        public float headExtendRange;
        public float headExtendRate;

        public float rightArmSwingRange;
        public float rightArmSwingRate;
        public float rightArmExtendRange;
        public float rightArmExtendRate;

        public float leftArmSwingRange;
        public float leftArmSwingRate;
        public float leftArmExtendRange;
        public float leftArmExtendRate;

        public float rightLegSwingRange;
        public float rightLegSwingRate;
        public float rightLegExtendRange;
        public float rightLegExtendRate;

        public float leftLegSwingRange;
        public float leftLegSwingRate;
        public float leftLegExtendRange;
        public float leftLegExtendRate;
    }

    class CritterNursery
    {
        #region Properties

        private const int BLINK_LENGTH = 12;
        private const int BLINK_LOCK = 36;

        static private Bitmap bmp = new Bitmap(10, 10, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

        Point eyeTarget = new Point(400, 400);

        Graphics gphx = Graphics.FromImage(bmp);

        Random dice = new Random();

        int blinkCount = 0;
        int blinkLock = BLINK_LOCK;
        #endregion

        #region GettersAndSetters


        public Point EyeTarget
        {
            set
            {
                eyeTarget = value;
            }
        }

        public Bitmap Bmp
        {
            get
            {
                return bmp;
            }

            set
            {
                bmp = value;
                gphx = Graphics.FromImage(bmp);
            }
        }

        #endregion

        #region Methods
       
        public void DrawCritter_000(Bitmap canvas, CritterType critter)
        {
            /*           j
             *         a /\b
             *       h__/  \__i        
             *        \ O  O /
             *        d\ -- /e
             *          \/\/
             *         f c g
             */
            Bmp = canvas;
            
            Pen pen          = new Pen(Color.FromArgb(255, 255, 0, 255));
            SolidBrush brush = new SolidBrush(Color.FromArgb(255, 0, 0, 255));

            brush.Color = Color.White;
            //gphx.FillRectangle(brush, 0, 0, bmp.Width, bmp.Height);

            int timeTicks = (int)DateTime.Now.Ticks;

            float up    = (float)Math.PI / 2.0f;
            float down  = up * 3.0f;
            float left  = (float)Math.PI;
            float right = 0.0f;
            
            //calculate the outline vertices of the body
            Point c = critter.bodyPosition;

            Point a = new Point(critter.bodyPosition.X - (int)(critter.bodyWidth/2), 
                                critter.bodyPosition.Y - (int)(critter.bodyHeight)+
                                (int)(critter.headAngle * 20));
            Point b = new Point(critter.bodyPosition.X + (int)(critter.bodyWidth / 2),
                                critter.bodyPosition.Y - (int)(critter.bodyHeight)-
                                (int)(critter.headAngle * 20));

            Point mid_ab = new Point((a.X + b.X) / 2, (a.Y + b.Y) / 2);

            Point d = new Point(critter.bodyPosition.X - (int)(critter.waistWidth / 2),
                                critter.bodyPosition.Y);
            Point e = new Point(critter.bodyPosition.X + (int)(critter.waistWidth / 2),
                                critter.bodyPosition.Y);

            Point mid_ad = new Point((d.X + a.X) / 2, (d.Y + a.Y) / 2);

            Point mid_be = new Point((b.X + e.X) / 2, (b.Y + e.Y) / 2);

            Point mid_dc = new Point((d.X + c.X) / 2, (d.Y + c.Y) / 2);

            Point mid_ce = new Point((c.X + e.X) / 2, (c.Y + e.Y) / 2);            

            Point j = new Point(mid_ab.X + (int)(Math.Cos(up + critter.headAngle) * critter.headHeight),
                                mid_ab.Y - (int)(Math.Sin(up + critter.headAngle) * critter.headHeight));

            Point f = new Point(mid_dc.X + (int)(Math.Cos(down + critter.leftLegAngle) * critter.leftLegLength),
                                mid_dc.Y - (int)(Math.Sin(down + critter.leftLegAngle) * critter.leftLegLength));

            Point g = new Point(mid_ce.X + (int)(Math.Cos(down + critter.rightLegAngle) * critter.rightLegLength),
                                mid_ce.Y - (int)(Math.Sin(down + critter.rightLegAngle) * critter.rightLegLength));

            Point h = new Point(mid_ad.X + (int)(Math.Cos(left + critter.leftArmAngle) * critter.leftArmLength),
                                mid_ad.Y - (int)(Math.Sin(left + critter.leftArmAngle) * critter.leftArmLength));

            Point i = new Point(mid_be.X + (int)(Math.Cos(right + critter.rightArmAngle) * critter.rightArmLength),
                                mid_be.Y - (int)(Math.Sin(right + critter.rightArmAngle) * critter.rightArmLength));

            GraphicsPath bodyOutline = new GraphicsPath();
            //i, e, g, c, f, d, h,
            Point[] bodyVertices = {j, b, i, e,g, c, f,d,h,a};

            bodyOutline.AddClosedCurve(bodyVertices, critter.curve);
            bodyOutline.CloseFigure();

            brush.Color = critter.backColour;
            pen.Color = critter.foreColour;
            pen.Width = 2.5f;


            gphx.FillPath(brush, bodyOutline);
            gphx.DrawPath(pen, bodyOutline);
            //draw mouth

            Point k = new Point((mid_dc.X + a.X) / 2, (mid_dc.Y + a.Y) / 2);
            Point l = new Point((mid_ce.X + b.X) / 2, (mid_ce.Y + b.Y) / 2);
            Point m = new Point(c.X, (k.Y + mid_dc.Y) / 2);
            Point n = new Point(m.X, (m.Y + c.Y) / 2);
            

            GraphicsPath mouthOutline = new GraphicsPath();
            Point[] mouthVertices = { k, m, l, n };
            mouthOutline.AddClosedCurve(mouthVertices, 1.5f);
            mouthOutline.CloseFigure();

            brush.Color = Color.Black;
            pen.Color = critter.foreColour;
            pen.Width = 2.5f;


            gphx.FillPath(brush, mouthOutline);
            gphx.DrawPath(pen, mouthOutline);
            //draw eyes
            float eyeRadius = Math.Abs(a.X - b.X) / 3.0f;

            Point eyeOriginL = a;

            Rectangle eyePlacementL = new Rectangle(eyeOriginL.X - (int)eyeRadius,
                                                   eyeOriginL.Y - (int)eyeRadius,
                                                   (int)eyeRadius * 2,
                                                   (int)eyeRadius * 2);

            Point eyeOriginR = b;

            Rectangle eyePlacementR = new Rectangle(eyeOriginR.X - (int)eyeRadius,
                                                   eyeOriginR.Y - (int)eyeRadius,
                                                   (int)eyeRadius * 2,
                                                   (int)eyeRadius * 2);
            blinkLock--;
            if (!((blinkCount > 0) && (blinkLock >= 0)))
            {
                //blink
                blinkLock = BLINK_LOCK;
                gphx.DrawLine(new Pen(Color.Black),
                              eyeOriginR.X - (int)eyeRadius,
                              eyeOriginR.Y,
                              eyeOriginR.X + (int)eyeRadius,
                              eyeOriginR.Y);

                gphx.DrawLine(new Pen(Color.Black),
                              eyeOriginL.X - (int)eyeRadius,
                              eyeOriginL.Y,
                              eyeOriginL.X + (int)eyeRadius,
                              eyeOriginL.Y);

                blinkCount--;
            }
            else
            {
                //draw eyes open


                pen.Color = Color.Black;
                brush.Color = Color.White;
                gphx.DrawEllipse(pen,
                                   eyePlacementL.X,
                                   eyePlacementL.Y,
                                   (int)eyeRadius * 2,
                                   (int)eyeRadius * 2);

                gphx.FillEllipse(brush,
                                   eyePlacementL.X,
                                   eyePlacementL.Y,
                                   (int)eyeRadius * 2,
                                   (int)eyeRadius * 2);

                gphx.DrawEllipse(pen,
                                 eyePlacementR.X,
                                 eyePlacementR.Y,
                                 (int)eyeRadius * 2,
                                 (int)eyeRadius * 2);

                gphx.FillEllipse(brush,
                                   eyePlacementR.X,
                                   eyePlacementR.Y,
                                   (int)eyeRadius * 2,
                                   (int)eyeRadius * 2);



                //eye pupil
                float distanceTarget = (float)(Math.Sqrt( Math.Pow(eyeOriginL.X - eyeTarget.X, 2) + 
                                                          Math.Pow(eyeOriginL.Y - eyeTarget.Y, 2)));
                

                brush.Color = Color.Black;
                
                float pupilRadius = eyeRadius / 2.0f;
                PointF pupilDelta = new PointF((( (eyeOriginL.X - eyeTarget.X) / distanceTarget) * (pupilRadius/2)), 
                                               (( (eyeOriginL.Y - eyeTarget.Y) / distanceTarget) * (pupilRadius/2))); 
                gphx.DrawEllipse(pen,
                                   eyeOriginL.X - (int)pupilRadius - pupilDelta.X,
                                   eyeOriginL.Y - (int)pupilRadius - pupilDelta.Y,
                                   (int)(pupilRadius * 2),
                                   (int)(pupilRadius * 2));

                gphx.FillEllipse(brush, eyeOriginL.X - (int)(pupilRadius) - pupilDelta.X,
                                   eyeOriginL.Y - (int)(pupilRadius) - pupilDelta.Y,
                                   (int)(pupilRadius * 2),
                                   (int)(pupilRadius * 2));

                gphx.DrawEllipse(pen,
                                     eyeOriginR.X - (int)(pupilRadius) - pupilDelta.X,
                                     eyeOriginR.Y - (int)(pupilRadius) - pupilDelta.Y,
                                     (int)(pupilRadius * 2),
                                     (int)(pupilRadius * 2));

                gphx.FillEllipse(brush, eyeOriginR.X - (int)(pupilRadius) - pupilDelta.X,
                                   eyeOriginR.Y - (int)(pupilRadius) - pupilDelta.Y,
                                   (int)(pupilRadius * 2),
                                   (int)(pupilRadius * 2));
            }
            
        }

        public void GetCritterFrame(Bitmap canvas, CritterType critter, CritterMotionType motion, int frame)
        {
            CritterType currentFrame = critter;

            currentFrame.headAngle = critter.headAngle + 
                                     (float)Math.Sin(frame * motion.headSwingRate) * 
                                     motion.headSwingRange;
            currentFrame.headHeight = critter.headHeight +
                                      (float)Math.Cos(frame * motion.headExtendRate) *
                                      motion.headExtendRange;

            currentFrame.leftArmAngle = critter.leftArmAngle +
                         (float)Math.Sin(frame * motion.leftArmSwingRate) *
                         motion.leftArmSwingRange;
            currentFrame.leftArmLength = critter.leftArmLength +
                                      (float)Math.Cos(frame * motion.leftArmExtendRate) *
                                      motion.leftArmExtendRange;

            currentFrame.rightArmAngle = critter.rightArmAngle +
                         (float)Math.Cos(frame * motion.rightArmSwingRate) *
                         motion.rightArmSwingRange;
            currentFrame.rightArmLength = critter.rightArmLength +
                                      (float)Math.Sin(frame * motion.rightArmExtendRate) *
                                      motion.rightArmExtendRange;

            currentFrame.leftLegAngle = critter.leftLegAngle +
                         (float)Math.Cos(frame * motion.leftLegSwingRate) *
                         motion.leftLegSwingRange;
            currentFrame.leftLegLength = critter.leftLegLength +
                                      (float)Math.Sin(frame * motion.leftLegExtendRate) *
                                      motion.leftLegExtendRange;

            currentFrame.rightLegAngle = critter.rightLegAngle +
                         (float)Math.Sin(frame * motion.rightLegSwingRate) *
                         motion.rightLegSwingRange;
            currentFrame.rightLegLength = critter.rightLegLength +
                                      (float)Math.Cos(frame * motion.rightLegExtendRate) *
                                      motion.rightLegExtendRange;

            DrawCritter_000(canvas, currentFrame);
        }

        public void Blink()
        {
            if (blinkCount == 0)
            {
                blinkCount = BLINK_LENGTH;
            }
            
        }
        #endregion
    }
}
